#include "proc.h"
#include "fs/fat32.h"
#include "fs/file.h"
#include "lock.h"
#include "mmu.h"
#include "mmulayout.h"
#include "riscv.h"
#include "stddef.h"
#include "stdio.h"
#include "string.h"
#include "trap.h"
#include "type.h"

#include "dbg.h"
code_t initcode[] = {
    
};

void proc_init(void)
{
    __DEBUG_FUNC_START;
    proc_t *p;
    spinlock_init(&pid_lk, "proc");
    for(p = proc; p < &proc[NPROC]; p++)
    {
        p->state = UNUSED;
        spinlock_init(&p->lk, "proc");
    }
    for(int i = 0; i < NCPUS; i++)
    {
        cpu[i].lk_num = 0;
        cpu[i].current_p = NULL;
    }
    __DEBUG_FUNC_END;
}

cpu_t * getCurrentCPU(void)
{
    return &cpu[r_tp()];
}

proc_t *getCurrentProc(void)
{
    intr_push();
    proc_t *p = getCurrentCPU()->current_p;   
    intr_pop();
    return p;   //TODO
}

pid_t alloc_pid(void)
{
    uint32_t c_pid;
    spinlock_acquire(&pid_lk);
    pid++;
    c_pid = pid;
    spinlock_release(&pid_lk);
    return c_pid;
}

proc_t * alloc_proc(void)
{
    __DEBUG_FUNC_START;
    proc_t *p;
    for(p = proc; p < &proc[NPROC]; p++)
    {
        spinlock_acquire(&p->lk);
        if(p->state == UNUSED)
        {
            break;
        }
        spinlock_release(&p->lk);
    }
    p->state = NEW;
    spinlock_release(&p->lk);
    p->pid = alloc_pid();
    alloc_proc_mem(p);
    p->kstack = (void *)UVK_STACK;
    memset(&p->context, 0, sizeof(p->context));
    p->context.ra = (uint64_t)entry_user_space;
    p->context.sp = (address_t)p->kstack + PAGE_SIZE;
    p->cwd = &root;
    p->openFiles[STDIN] = (file_t*)STDIN_PTR;
    p->openFiles[STDOUT] = (file_t*)STDOUT_PTR;
    p->openFiles[STDERR] = (file_t*)STDERR_PTR;
    p->isForked = 0;
    p->heap = NULL;
    p->chan = NULL;
    p->tms.tms_cstime = 0;
    p->tms.tms_cutime = 0;
    p->tms.tms_stime = 0;
    p->tms.tms_utime = 0;
    p->tms.entry_kernel = 0;
    p->tms.leave_kernel = 0;
    __DEBUG_FUNC_END;
    return p;
}

void creat_first_proc(void)
{
    __DEBUG_FUNC_START;
    proc_t *p;
    p = alloc_proc();
    uvminit(p->upageTable, p->kpageTable, initcode, (uint64_t)sizeof(initcode));
    p->trapFrame->sp = PAGE_SIZE;
    p->trapFrame->u_pc = 0x0;
    p->state = READY;
    __DEBUG_FUNC_END;
}

void entry_user_space(void)
{
    static int flag = 0;
    proc_t *p = getCurrentProc();
    spinlock_release(&p->lk);
    if(flag == 0)
    {
        fat32_init();
        flag = 1;
    }
    else 
    {
        elf_load(p, p->path);
    }
    usertrapret();
}




